﻿// Decompiled with JetBrains decompiler
// Type: MCM.Implementation.PerSave.PerSaveSettingsContainer
// Assembly: MCMv5, Version=5.10.2.0, Culture=neutral, PublicKeyToken=null
// MVID: 7AB326B9-B2B4-41C2-9177-68E944071101
// Assembly location: D:\steam\steamapps\workshop\content\261550\2859238197\bin\Win64_Shipping_Client\MCMv5.dll

using BUTR.DependencyInjection;
using BUTR.DependencyInjection.Logger;
using HarmonyLib.BUTR.Extensions;
using MCM.Abstractions;
using MCM.Abstractions.Base;
using MCM.Abstractions.Base.PerSave;
using MCM.Abstractions.GameFeatures;
using MCM.Abstractions.PerSave;
using MCM.Common;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

#nullable enable
namespace MCM.Implementation.PerSave
{
  internal sealed class PerSaveSettingsContainer : 
    BaseSettingsContainer<PerSaveSettings>,
    IPerSaveSettingsContainer,
    ISettingsContainer,
    ISettingsContainerHasSettingsDefinitions,
    ISettingsContainerCanOverride,
    ISettingsContainerCanReset,
    ISettingsContainerPresets,
    ISettingsContainerHasUnavailable,
    ISettingsContainerHasSettingsPack,
    ISettingsContainerCanInvalidateCache
  {
    private readonly IBUTRLogger _logger;
    private readonly IGameEventListener _gameEventListener;
    private bool _hasGameStarted;

    public event Action? InstanceCacheInvalidated;

    public PerSaveSettingsContainer(
      IBUTRLogger<PerSaveSettingsContainer> logger,
      IGameEventListener gameEventListener)
    {
      this._logger = (IBUTRLogger) logger;
      this._gameEventListener = gameEventListener;
      this._gameEventListener.GameStarted += new Action(this.GameStarted);
      this._gameEventListener.GameEnded += new Action(this.GameEnded);
    }

    protected override void RegisterSettings(PerSaveSettings? perSaveSettings)
    {
      if (GenericServiceProvider.GameScopeServiceProvider == null)
        return;
      IPerSaveSettingsProvider service = GenericServiceProvider.GetService<IPerSaveSettingsProvider>();
      if (service == null || perSaveSettings == null)
        return;
      this.LoadedSettings.Add(perSaveSettings.Id, perSaveSettings);
      service.LoadSettings(perSaveSettings);
      perSaveSettings.OnPropertyChanged("LOADING_COMPLETE");
    }

    public override bool SaveSettings(BaseSettings settings)
    {
      if (GenericServiceProvider.GameScopeServiceProvider == null)
        return false;
      IPerSaveSettingsProvider service = GenericServiceProvider.GetService<IPerSaveSettingsProvider>();
      if (service == null || !(settings is PerSaveSettings perSaveSettings) || !this.LoadedSettings.ContainsKey(perSaveSettings.Id))
        return false;
      service.SaveSettings(perSaveSettings);
      settings.OnPropertyChanged("SAVE_TRIGGERED");
      return true;
    }

    private void GameStarted()
    {
      this._hasGameStarted = true;
      Action cacheInvalidated = this.InstanceCacheInvalidated;
      if (cacheInvalidated != null)
        cacheInvalidated();
      this.LoadedSettings.Clear();
    }

    private IEnumerable<PerSaveSettings> GetPerSaveSettings()
    {
      foreach (Assembly assembly in AccessTools2.AllAssemblies().Where<Assembly>((Func<Assembly, bool>) (a => !a.IsDynamic)))
      {
        IEnumerable<PerSaveSettings> settings;
        try
        {
          settings = (IEnumerable<PerSaveSettings>) ((IEnumerable<Type>) AccessTools2.GetTypesFromAssemblyIfValid(assembly)).Where<Type>((Func<Type, bool>) (t => t.IsClass && !t.IsAbstract)).Where<Type>((Func<Type, bool>) (t => (object) t.GetConstructor(Type.EmptyTypes) != null)).Where<Type>((Func<Type, bool>) (t => typeof (PerSaveSettings).IsAssignableFrom(t))).Where<Type>((Func<Type, bool>) (t => !typeof (EmptyPerSaveSettings).IsAssignableFrom(t))).Where<Type>((Func<Type, bool>) (t => !typeof (IWrapper).IsAssignableFrom(t))).Select<Type, PerSaveSettings>((Func<Type, PerSaveSettings>) (t =>
          {
            try
            {
              return Activator.CreateInstance(t) as PerSaveSettings;
            }
            catch (Exception ex1)
            {
              try
              {
                this._logger.LogError(ex1, string.Format("Failed to initialize type {0}", (object) t));
              }
              catch (Exception ex2)
              {
                this._logger.LogError(ex1, "Failed to initialize and log type!");
              }
              return (PerSaveSettings) null;
            }
          })).OfType<PerSaveSettings>().ToList<PerSaveSettings>();
        }
        catch (TypeLoadException ex)
        {
          settings = (IEnumerable<PerSaveSettings>) Array.Empty<PerSaveSettings>();
          this._logger.LogError((Exception) ex, string.Format("Error while handling assembly {0}!", (object) assembly));
        }
        foreach (PerSaveSettings setting in settings)
          yield return setting;
        settings = (IEnumerable<PerSaveSettings>) null;
      }
    }

    public void LoadSettings()
    {
      foreach (PerSaveSettings perSaveSetting in this.GetPerSaveSettings())
        this.RegisterSettings(perSaveSetting);
    }

    public IEnumerable<UnavailableSetting> GetUnavailableSettings()
    {
      return this._hasGameStarted ? (IEnumerable<UnavailableSetting>) Array.Empty<UnavailableSetting>() : this.GetPerSaveSettings().Select<PerSaveSettings, UnavailableSetting>((Func<PerSaveSettings, UnavailableSetting>) (setting => new UnavailableSetting(setting.Id, setting.DisplayName, UnavailableSettingType.PerSave)));
    }

    private void GameEnded()
    {
      this._hasGameStarted = false;
      Action cacheInvalidated = this.InstanceCacheInvalidated;
      if (cacheInvalidated != null)
        cacheInvalidated();
      this.LoadedSettings.Clear();
    }
  }
}
